package com.cq.music;

import com.cq.music.util.Logger;
import ohos.aafwk.content.Intent;
import ohos.ace.ability.AceInternalAbility;
import ohos.app.AbilityContext;
import ohos.app.Context;
import ohos.bluetooth.BluetoothHost;
import ohos.bluetooth.ProfileBase;
import ohos.bluetooth.ble.*;
import ohos.event.commonevent.*;
import ohos.hiviewdfx.HiLog;
import ohos.rpc.IRemoteObject;
import ohos.rpc.MessageOption;
import ohos.rpc.MessageParcel;
import ohos.rpc.RemoteException;
import ohos.utils.SequenceUuid;
import ohos.utils.zson.ZSONObject;

import java.io.PipedInputStream;
import java.net.URLConnection;
import java.util.*;

public class BlueToothAbility extends AceInternalAbility {
    private static final String BUNDLE_NAME = "com.cq.music";
    //    定义ABILITY_NAME
    private static final String ABILITY_NAME = "com.cq.music.BlueToothAbility";
    private static final int GET_BLU_SATATUS_CODE = 1000;
    private static final int GO_BLU_OPEN_CODE = 1001;
    private static final int GO_BLU_CLOSE_CODE = 1002;
    private static final int SUBSCRIBE_BLUE_STATE = 1003;
    private static final int UNSUBSCRIBE_BLUE_STATE = 1004;
    private static final int BLE_SCAN_CODE = 1005;
    private static final int STOP_BLE_SCAN_CODE = 1006;
    private static final int CONNECT_BLE_CODE = 1008;
    private static final int GET_BLE_SCAN_RESULT_CODE = 1007;

    //    B35921DD35D250DAB53E8BADBD00DBE6ECEE9F4201F2008490C224408ACA8DD5 设备ID
    IRemoteObject iRemoteObject;
    IRemoteObject resultRemoteObject;

    public static BlueToothAbility instance;
    public static AbilityContext abilityContext; //上下文
    BluetoothHost bluetoothHost;
    private BleCentralManager centralManager;

    //  private List<String> addrList = new ArrayList();

    private List<BlePeripheralDevice> blePeripheralDeviceList = new ArrayList();

    private BlueToothAbility() {
        super(BUNDLE_NAME, ABILITY_NAME);
    }

    //    定义拿到蓝牙状态方法
    public static void register(AbilityContext abilityContext) {
//        赋值 instance 为BlueToothAbility对象
        instance = new BlueToothAbility();
//        对象上的方法
        instance.onRegister(abilityContext);

    }

    private void onRegister(AbilityContext abilityContext) {
        this.abilityContext = abilityContext;
        bluetoothHost = BluetoothHost.getDefaultHost(abilityContext);

        subscribeBluetoothEvents();
//        开始通信js与Java之间
        this.setInternalAbilityHandler(new AceInternalAbilityHandler() {
            @Override
            public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption messageOption) throws RemoteException {
                switch (code) {
//                    case执行指令
                    case GET_BLU_SATATUS_CODE: {
//                        真正获取状态码的地方
                        int bluStatus = getBluStatus();
                        Logger.d("cqlog bluStatus = " + bluStatus);
                        Map<String, Object> ret = new HashMap<String, Object>();
                        ret.put("status", bluStatus);
                        reply.writeString(ZSONObject.toZSONString(ret));
                    }
                    break;
                    case GO_BLU_OPEN_CODE: {
                        boolean enableBt = enableBt();
                        Logger.d("cqlog enableBt = " + enableBt);
                        Map<String, Object> ret = new HashMap<String, Object>();
                        ret.put("isOpen", enableBt);
                        reply.writeString(ZSONObject.toZSONString(ret));
                    }
                    break;
                    case GO_BLU_CLOSE_CODE: {
                        boolean disableBt = bluetoothHost.disableBt();
                        Logger.d("cqlog disableBt = " + disableBt);
                        Map<String, Object> ret = new HashMap<>();
                        ret.put("isClose", disableBt);
                        reply.writeString(ZSONObject.toZSONString(ret));
                    }
                    break;
                    case SUBSCRIBE_BLUE_STATE:
                        iRemoteObject = data.readRemoteObject();
                        break;
                    case UNSUBSCRIBE_BLUE_STATE: {
                        iRemoteObject = null;
                    }
                    break;
                    case BLE_SCAN_CODE: {
                        resultRemoteObject = data.readRemoteObject();
                        startScan(new ArrayList<>());
                    }
                    break;
                    case STOP_BLE_SCAN_CODE: {
                        stopScan();
                    }
                    break;
//                    case GET_BLE_SCAN_RESULT_CODE:{
//                        resultRemoteObject = data.readRemoteObject();
//                        Logger.d("cqlog resultRemoteObject = " + resultRemoteObject);
//                    }
                    //    break;
                    case CONNECT_BLE_CODE: {
                        String dataStr = data.readString();
                        ZSONObject zsonObject = ZSONObject.stringToZSON(dataStr);
                        String deviceAddr = zsonObject.getString("addr");
                        Logger.d("addr =" + deviceAddr);
                        BlePeripheralDevice instance = BlePeripheralDevice.createInstance(deviceAddr);
                        connectBle(instance);
                    }
                    break;
                }
                return true;
            }
        });
    }


    CommonEventSubscriber commonEventSubscriber;

    private void subscribeBluetoothEvents() {
        MatchingSkills matchingSkills = new MatchingSkills();
        matchingSkills.addEvent(BluetoothHost.EVENT_HOST_STATE_UPDATE);
        CommonEventSubscribeInfo subscribeInfo = new CommonEventSubscribeInfo(matchingSkills);
        commonEventSubscriber = new CommonEventSubscriber(subscribeInfo) {

            @Override
            public void onReceiveEvent(CommonEventData commonEventData) {
                Intent intent = commonEventData.getIntent();
                handleIntent(intent);
            }
        };
        try {
            CommonEventManager.subscribeCommonEvent(commonEventSubscriber);
        } catch (RemoteException exception) {
            exception.printStackTrace();
        }
    }

    private void handleIntent(Intent intent) {
        if (intent == null) {
            return;
        }
        String action = intent.getAction();
        switch (action) {
            case BluetoothHost.EVENT_HOST_STATE_UPDATE:
                int bluStatus = getBluStatus();
                sendBluStateCallBackJs(bluStatus);
                Logger.d("cqlog getBluStatus = " + bluStatus);
                break;
            default:
                break;
        }
    }

    private void sendBluStateCallBackJs(int bluStatus) {
        if (iRemoteObject == null) return;
        MessageParcel responseData = MessageParcel.obtain();
        MessageParcel reply = MessageParcel.obtain();
        Map<String, Object> ret = new HashMap<String, Object>();
        ret.put("status", bluStatus);
        responseData.writeString(ZSONObject.toZSONString(ret));
        try {
            iRemoteObject.sendRequest(0, responseData, reply, new MessageOption());
            responseData.reclaim();
            reply.reclaim();
        } catch (RemoteException exception) {
            Logger.e("exception :" + exception);
        }
    }

    private int getBluStatus() {
        // BluetoothHost bluetoothHost = BluetoothHost.getDefaultHost(abilityContext);
        // 调用获取蓝牙开关状态接口
        int state = bluetoothHost.getBtState();
        Logger.d("state:" + state);
        return state;
    }

    /**
     * 打开蓝牙
     *
     * @return true打开蓝牙动作执行
     */
    private boolean enableBt() {
        boolean enable = bluetoothHost.enableBt();
        return enable;
    }

    //中心广播
    public void startScan(List<BleScanFilter> filters) {
        centralManager = new BleCentralManager(abilityContext, new MyBleCentralManagerCallback());
        centralManager.startScan(filters);
    }

    public void stopScan() {
        centralManager.stopScan();
        Logger.d("stopScan 成功停止扫描");
    }

    private class MyBleCentralManagerCallback implements BleCentralManagerCallback {

        @Override
        public void scanResultEvent(BleScanResult bleScanResult) {
            String deviceAddr = bleScanResult.getPeripheralDevice().getDeviceAddr();
            BlePeripheralDevice peripheralDevice = bleScanResult.getPeripheralDevice();
            Optional<String> optional = bleScanResult.getPeripheralDevice().getDeviceName();
            String deviceName = "未知名称";
            boolean present = optional.isPresent();
            if (!present) return;


            for (BlePeripheralDevice device : blePeripheralDeviceList) {
                if (device.getDeviceAddr().equals(deviceAddr)) {
                    return;
                }
            }
            blePeripheralDeviceList.add(peripheralDevice);

            if (present) {
                deviceName = optional.get();
            }
            Logger.d("扫描到相关设备 deviceName = " + deviceName);
            sendBleScanDeviceCallbackJs(deviceName, deviceAddr);
        }

        @Override
        public void scanFailedEvent(int event) {
            Logger.d("扫描到相关设备 BleScanResult = " + event);
        }

        @Override
        public void groupScanResultsEvent(List<BleScanResult> list) {
            //使用组扫描是在此对扫描结果进行处理
        }
    }

    private void sendBleScanDeviceCallbackJs(String deviceName, String deviceAddr) {
        if (resultRemoteObject == null) return;
        MessageParcel responseData = MessageParcel.obtain();
        MessageParcel reply = MessageParcel.obtain();
        Map<String, Object> ret = new HashMap<String, Object>();
        ret.put("name", deviceName);
        ret.put("addr", deviceAddr);
        responseData.writeString(ZSONObject.toZSONString(ret));
        try {
            resultRemoteObject.sendRequest(0, responseData, reply, new MessageOption());
            responseData.reclaim();
            reply.reclaim();
        } catch (RemoteException exception) {
            Logger.e("value :" + deviceName);
        }
    }

    BlePeripheralDevice peripheraDevice;

    public void connectBle(BlePeripheralDevice peripheraDevice) {
        this.peripheraDevice = peripheraDevice;
        MyBlePeripheralCallback callback = new MyBlePeripheralCallback();
        boolean connect = peripheraDevice.connect(false, callback);
        Logger.d("connect :" + connect);
//
    }


    public class MyBlePeripheralCallback extends BlePeripheralCallback {

        @Override
        public void connectionStateChangeEvent(int connectionState) {
            super.connectionStateChangeEvent(connectionState);
            Logger.d("cqlog   connectionState: " + connectionState);
            if (connectionState == ProfileBase.STATE_CONNECTED) {
                Logger.d("连接成功");
                peripheraDevice.discoverServices();
            }
        }

        @Override
        public void servicesDiscoveredEvent(int status) {
            super.servicesDiscoveredEvent(status);
            if (status == BlePeripheralDevice.OPERATION_SUCC) {
                Logger.d("发现服务成功 servicesDiscoveredEvent()");
                for (GattService service : peripheraDevice.getServices()) {
                    checkGattCharacteristic(service);
                }
            }
        }
    }


    private static int READ = 0x2;
    private static int WRITE = 0x8;
    private static int NOTIFY = 0x10;


    private void checkGattCharacteristic(GattService service) {

        for (GattCharacteristic tmpChara : service.getCharacteristics()) {
            int properties = tmpChara.getProperties();
            if (properties == READ){
                Logger.d(" getProperties = " + properties);
            }

            if (properties == WRITE){
                Logger.d(" getProperties = " + properties);
            }

            if (properties == NOTIFY){
                Logger.d(" getProperties = " + properties);
            }

            Logger.d(" getUuid = " + tmpChara.getUuid());
        }
    }

    public static void unregister() {
        instance.onUnregister();
    }

    //真正的注销
    private void onUnregister() {
//        将上下文改为null
        abilityContext = null;
//        将通信内的参数改为null，获取不到对应数据，销毁注销
        this.setInternalAbilityHandler(null);
        try {
            CommonEventManager.unsubscribeCommonEvent(commonEventSubscriber);
        } catch (RemoteException exception) {
            exception.printStackTrace();
        }
    }
}
